﻿namespace FFF.Test.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Linq;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json;
    using Senparc.CO2NET.Cache;
    using Senparc.CO2NET.Extensions;
    using Senparc.CO2NET.HttpUtility;
    using Senparc.CO2NET.Utilities;
    using Senparc.Weixin;
    using Senparc.Weixin.Entities.TemplateMessage;
    using Senparc.Weixin.Exceptions;
    using Senparc.Weixin.MP;
    using Senparc.Weixin.MP.AdvancedAPIs;
    using Senparc.Weixin.MP.AdvancedAPIs.OAuth;
    using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage;
    using Senparc.Weixin.TenPay.V3;
    using Senparc.Weixin.WxOpen.AdvancedAPIs.Sns;
    using Senparc.Weixin.WxOpen.Containers;
    using Senparc.Weixin.WxOpen.Entities;
    using Senparc.Weixin.WxOpen.Entities.Request;
    using Senparc.Weixin.WxOpen.Helpers;
    using FFF.Test.Application.AppServices.WX;
    using FFF.Test.Application.Framework.Dto;
    using FFF.Test.Entity.WX.Dto;
    using FFF.Test.Util.Consts;
    using FFF.Test.Util.Web;
    using Ydm.Helper;

    /// <summary>
    /// 微信小程序Controller
    /// </summary>
    public partial class WxController : YdmAbpControllerBase
    {
        private static readonly string Token = Config.SenparcWeixinSetting.Token; // 与微信小程序后台的Token设置保持一致，区分大小写。
        private static readonly string EncodingAESKey = Config.SenparcWeixinSetting.EncodingAESKey; // 与微信小程序后台的EncodingAESKey设置保持一致，区分大小写。
        private static readonly string AppId = Config.SenparcWeixinSetting.WeixinAppId; // 与微信小程序后台的AppId设置保持一致，区分大小写。
        private static readonly string AppSecret = Config.SenparcWeixinSetting.WeixinAppSecret; // 与微信小程序账号后台的AppId设置保持一致，区分大小写。

        private readonly Func<string> _getRandomFileName = () => DateTime.Now.ToString("yyyyMMdd-HHmmss") + Guid.NewGuid().ToString("n").Substring(0, 6);

        private static TenPayV3Info TenPayV3Info { get; set; } = TenPayV3InfoCollection.Data[Config.SenparcWeixinSetting.TenPayV3_MchId + "_"];

        private readonly IWXUserInfoAppService _wXUserInfoAppService;

        /// <summary>
        /// Initializes a new instance of the <see cref="WxController"/> class.
        /// 微信controller
        /// </summary>
        /// <param name="wXUserInfoAppService">微信用户服务类</param>
        public WxController(IWXUserInfoAppService wXUserInfoAppService)
        {
            this._wXUserInfoAppService = wXUserInfoAppService;
        }

        /// <summary>
        /// GET请求用于处理微信小程序后台的URL验证
        /// </summary>
        /// <param name="postModel">微信传的model</param>
        /// <param name="echostr">随机字符</param>
        /// <returns>actionresult</returns>
        [HttpGet]
        [ActionName("Index")]
        [AllowAnonymous]
        public ActionResult Get(PostModel postModel, string echostr)
        {
            if (CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token))
            {
                return base.Content(echostr); // 返回随机字符串则表示验证通过
            }
            else
            {
                return base.Content("failed:" + postModel.Signature + "," + CheckSignature.GetSignature(postModel.Timestamp, postModel.Nonce, Token) + "。" +
                    "如果你在浏览器中看到这句话，说明此地址可以被作为微信小程序后台的Url，请注意保持Token一致。");
            }
        }

        #region 微信用户验证

        /// <summary>
        /// 微信授权访问
        /// </summary>
        /// <returns>actionresult</returns>
        [HttpGet]
        [WxAuthor]
        public ActionResult WxTest()
        {
            return base.Content("我需要微信授权才能访问");
        }

        /// <summary>
        /// 校验用户是否登陆
        /// </summary>
        /// <param name="redirct">返回的地址</param>
        /// <returns>actionresult</returns>
        [HttpGet]
        [AllowAnonymous]
        public ActionResult ValidateUserInfo(string redirct)
        {
            var state = "JeffreySu-" + DateTime.Now.Millisecond; //随机数，用于识别请求可靠性
            base.HttpContext.Session.SetString("State", state); //储存随机数到Session
            string domain = AppConfigConsts.AppDomain;
            var url = OAuthApi.GetAuthorizeUrl(
              AppId,
              $"{domain}/Wx/UserInfoCallback?redirct=" + redirct.UrlEncode(),
              state,
              OAuthScope.snsapi_userinfo);
            return base.Redirect(url);
        }

        /// <summary>
        /// OAuthScope.snsapi_userinfo方式回调
        /// </summary>
        /// <param name="code">微信返回的code</param>
        /// <param name="state">状态校验</param>
        /// <param name="redirct">用户最初尝试进入的页面</param>
        /// <returns>跳转</returns>
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> UserInfoCallback(string code, string state, string redirct)
        {
            if (string.IsNullOrEmpty(code))
            {
                return base.Content("您拒绝了授权！");
            }

            if (state != base.HttpContext.Session.GetString("State"))
            {
                //这里的state其实是会暴露给客户端的，验证能力很弱，这里只是演示一下，
                //建议用完之后就清空，将其一次性使用
                //实际上可以存任何想传递的数据，比如用户ID，并且需要结合例如下面的Session["OAuthAccessToken"]进行验证
                return base.Content("验证失败！请从正规途径进入！");
            }

            OAuthAccessTokenResult result = OAuthApi.GetAccessToken(AppId, AppSecret, code);

            if (result.errcode != ReturnCode.请求成功)
            {
                return base.Content("错误：" + result.errmsg);
            }

            // OAuthUserInfo userInfo = OAuthApi.GetUserInfo(result.access_token, result.openid);

            var userInfo = UserApi.Info(AppId, result.openid);
            WXUserInfoCreateInputDto createDto = base.ObjectMapper.Map<WXUserInfoCreateInputDto>(userInfo);
            createDto.WeixinAppId = AppId;
            var wxDto = await this._wXUserInfoAppService.CreateByDto(createDto);
            PrimaryDto primaryDto = new PrimaryDto()
            {
                Id = wxDto.Id.ToString()
            };

            var viewDto = await this._wXUserInfoAppService.GetViewDto(primaryDto);
            base.HttpContext.Session.SetString(AppConfigConsts.WxUserInfo, JsonConvert.SerializeObject(viewDto));

            // 插入微信用户表
            if (!string.IsNullOrEmpty(redirct))
            {
                return base.Redirect(redirct);
            }

            return base.View(userInfo);
        }

        #endregion

        #region 支付相关

        /// <summary>
        /// 展示产品
        /// </summary>
        /// <returns>action展示</returns>
        [AllowAnonymous]
        public ActionResult ProductList()
        {
            var products = ProductModel.GetFakeProductList();
            return base.View(products);
        }

        /// <summary>
        /// 单个产品
        /// </summary>
        /// <param name="productId">产品Id</param>
        /// <param name="hc">产品验证</param>
        /// <returns>result</returns>
        [AllowAnonymous]
        public ActionResult ProductItem(int productId, int hc)
        {
            var products = ProductModel.GetFakeProductList();
            var product = products.FirstOrDefault(z => z.Id == productId);
            if (product == null || product.GetHashCode() != hc)
            {
                return base.Content("商品信息不存在，或非法进入！2003");
            }

            //判断是否正在微信端
            if (Senparc.Weixin.BrowserUtility.BrowserUtility.SideInWeixinBrowser(base.HttpContext))
            {
                //正在微信端，直接跳转到微信支付页面
                return base.RedirectToAction("JsApi", new { productId = productId, hc = hc });
            }
            else
            {
                //在PC端打开，提供二维码扫描进行支付
                return base.View(product);
            }
        }

        /// <summary>
        /// 显示二维码
        /// </summary>
        /// <param name="productId">产品ID</param>
        /// <param name="hc">验证</param>
        /// <returns>产品模型</returns>
        [AllowAnonymous]
        public ActionResult ProductPayCode(int productId, int hc)
        {
            var products = ProductModel.GetFakeProductList();
            var product = products.FirstOrDefault(z => z.Id == productId);
            if (product == null || product.GetHashCode() != hc)
            {
                return base.Content("商品信息不存在，或非法进入！2004");
            }

            string domain = AppConfigConsts.AppDomain;
            var url = string.Format(
                $"{domain}/Wx/JsApi?productId={0}&hc={1}&t={2}",
                 productId,
                  product.GetHashCode(),
                  SystemTime.Now.Ticks);
            var path = Server.MapPath($"~/{Guid.NewGuid()}.png");
            YdmQRCodeGenHelper.GenQrCode(path, url, 300, 300);
            var bytes = System.IO.File.ReadAllBytes(path);

            //BitMatrix bitMatrix;
            //bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 600, 600);
            //var bw = new ZXing.BarcodeWriterPixelData();

            //var pixelData = bw.Write(bitMatrix);
            //var bitmap = new System.Drawing.Bitmap(pixelData.Width, pixelData.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            //var fileStream = new MemoryStream();
            //var bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, pixelData.Width, pixelData.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            //try
            //{
            //    // we assume that the row stride of the bitmap is aligned to 4 byte multiplied by the width of the image   
            //    System.Runtime.InteropServices.Marshal.Copy(pixelData.Pixels, 0, bitmapData.Scan0, pixelData.Pixels.Length);
            //}
            //finally
            //{
            //    bitmap.UnlockBits(bitmapData);
            //}

            //fileStream.Flush(); //.net core 必须要加
            //fileStream.Position = 0; //.net core 必须要加

            //bitmap.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);

            //fileStream.Seek(0, SeekOrigin.Begin);
            System.IO.File.Delete(path);
            return base.File(bytes, "image/png");
        }

        /// <summary>
        /// Jsapi支付
        /// </summary>
        /// <param name="productId">jsapi支付</param>
        /// <param name="hc">验证码</param>
        /// <returns>action</returns>
        //[WxAuthor]
        [AllowAnonymous]
        public ActionResult JsApi(int productId, int hc)
        {
            try
            {
                //获取产品信息
                var products = ProductModel.GetFakeProductList();
                var product = products.FirstOrDefault(z => z.Id == productId);
                if (product == null || product.GetHashCode() != hc)
                {
                    return base.Content("商品信息不存在，或非法进入！1002");
                }

                // var openId = base.HttpContext.Session.GetWxUserInfo().Openid;

                var openId = "oetvtssitVb_m4BkcuiAE-UVBS1U";

                string sp_billno = base.Request.Query["order_no"];
                if (string.IsNullOrEmpty(sp_billno))
                {
                    //生成订单10位序列号，此处用时间和随机数生成，商户根据自己调整，保证唯一
                    sp_billno = string.Format(
                        "{0}{1}{2}",
                        TenPayV3Info.MchId,
                        DateTime.Now.ToString("yyyyMMddHHmmss"),
                        TenPayV3Util.BuildRandomStr(6));
                }
                else
                {
                    sp_billno = base.Request.Query["order_no"];
                }

                var timeStamp = TenPayV3Util.GetTimestamp();
                var nonceStr = TenPayV3Util.GetNoncestr();

                var body = product == null ? "test" : product.Name;
                var price = product == null ? 100 : (int)(product.Price * 100); //单位：分
                var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, body, sp_billno, price, base.HttpContext.UserHostAddress()?.ToString(), TenPayV3Info.TenPayV3Notify, Senparc.Weixin.TenPay.TenPayV3Type.JSAPI, openId, TenPayV3Info.Key, nonceStr);

                var result = TenPayV3.Unifiedorder(xmlDataInfo); //调用统一订单接口
                                                                 //JsSdkUiPackage jsPackage = new JsSdkUiPackage(TenPayV3Info.AppId, timeStamp, nonceStr,);
                var package = string.Format("prepay_id={0}", result.prepay_id);

                base.ViewData["product"] = product;

                base.ViewData["appId"] = TenPayV3Info.AppId;
                base.ViewData["timeStamp"] = timeStamp;
                base.ViewData["nonceStr"] = nonceStr;
                base.ViewData["package"] = package;
                base.ViewData["paySign"] = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key);

                //临时记录订单信息，留给退款申请接口测试使用
                base.HttpContext.Session.SetString("BillNo", sp_billno);
                base.HttpContext.Session.SetString("BillFee", price.ToString());

                return base.View();
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                msg += "<br>" + ex.StackTrace;
                msg += "<br>==Source==<br>" + ex.Source;

                if (ex.InnerException != null)
                {
                    msg += "<br>===InnerException===<br>" + ex.InnerException.Message;
                }

                return base.Content(msg);
            }
        }

        /// <summary>
        /// JS-SDK支付回调地址（在统一下单接口中设置notify_url）
        /// </summary>
        /// <returns>actinResult</returns>
        public ActionResult PayNotifyUrl()
        {
            try
            {
                ResponseHandler resHandler = new ResponseHandler(base.HttpContext);

                string return_code = resHandler.GetParameter("return_code");
                string return_msg = resHandler.GetParameter("return_msg");

                string res;

                resHandler.SetKey(TenPayV3Info.Key);

                //验证请求是否从微信发过来（安全）
                if (resHandler.IsTenpaySign() && return_code.ToUpper() == "SUCCESS")
                {
                    res = "success"; //正确的订单处理
                    //直到这里，才能认为交易真正成功了，可以进行数据库操作，但是别忘了返回规定格式的消息！
                }
                else
                {
                    res = "wrong"; //错误的订单处理
                }

                /* 这里可以进行订单处理的逻辑 */

                //发送支付成功的模板消息
                try
                {
                    string appId = Config.SenparcWeixinSetting.TenPayV3_AppId; //与微信公众账号后台的AppId设置保持一致，区分大小写。
                    string openId = resHandler.GetParameter("openid");
                    var templateData = new WeixinTemplate_PaySuccess("https://weixin.senparc.com", "购买商品", "状态：" + return_code);

                    WeixinTrace.SendCustomLog("支付成功模板消息参数", appId + " , " + openId);

                    var result = TemplateApi.SendTemplateMessage(appId, openId, templateData);
                }
                catch (Exception ex)
                {
                    WeixinTrace.SendCustomLog("支付成功模板消息错误", ex.ToString());
                }

                #region 记录日志

                var logDir = Server.MapPath(string.Format("~/App_Data/TenPayNotify/{0}", DateTime.Now.ToString("yyyyMMdd")));
                if (!Directory.Exists(logDir))
                {
                    Directory.CreateDirectory(logDir);
                }

                var logPath = Path.Combine(logDir, string.Format("{0}-{1}-{2}.txt", DateTime.Now.ToString("yyyyMMdd"), DateTime.Now.ToString("HHmmss"), Guid.NewGuid().ToString("n").Substring(0, 8)));

                using (var fileStream = System.IO.File.OpenWrite(logPath))
                {
                    var notifyXml = resHandler.ParseXML();

                    //fileStream.Write(Encoding.Default.GetBytes(res), 0, Encoding.Default.GetByteCount(res));

                    fileStream.Write(Encoding.Default.GetBytes(notifyXml), 0, Encoding.Default.GetByteCount(notifyXml));
                    fileStream.Close();
                }

                #endregion

                string xml = string.Format(
                    @"<xml> <return_code><![CDATA[{0}]]></return_code> <return_msg><![CDATA[{1}]]></return_msg></xml>",
                                        return_code,
                                        return_msg);
                return base.Content(xml, "text/xml");
            }
            catch (Exception ex)
            {
                WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex));
                throw;
            }
        }

        #endregion

        #region 订单及退款

        /// <summary>
        /// 订单查询
        /// </summary>
        /// <returns>result</returns>
        public ActionResult OrderQuery()
        {
            string nonceStr = TenPayV3Util.GetNoncestr();
            RequestHandler packageReqHandler = new RequestHandler(null);

            //设置package订单参数
            packageReqHandler.SetParameter("appid", TenPayV3Info.AppId);		  //公众账号ID
            packageReqHandler.SetParameter("mch_id", TenPayV3Info.MchId);		  //商户号
            packageReqHandler.SetParameter("transaction_id", string.Empty);       //填入微信订单号
            packageReqHandler.SetParameter("out_trade_no", string.Empty);         //填入商家订单号
            packageReqHandler.SetParameter("nonce_str", nonceStr);             //随机字符串
            string sign = packageReqHandler.CreateMd5Sign("key", TenPayV3Info.Key);
            packageReqHandler.SetParameter("sign", sign);	                    //签名

            string data = packageReqHandler.ParseXML();

            var result = TenPayV3.OrderQuery(data);
            var res = XDocument.Parse(result);
            string openid = res.Element("xml").Element("sign").Value;

            return base.Content(openid);
        }

        /// <summary>
        /// 关闭订单接口
        /// </summary>
        /// <returns>result</returns>
        public ActionResult CloseOrder()
        {
            string nonceStr = TenPayV3Util.GetNoncestr();
            RequestHandler packageReqHandler = new RequestHandler(null);

            //设置package订单参数
            packageReqHandler.SetParameter("appid", TenPayV3Info.AppId);		  //公众账号ID
            packageReqHandler.SetParameter("mch_id", TenPayV3Info.MchId);		  //商户号
            packageReqHandler.SetParameter("out_trade_no", string.Empty);                 //填入商家订单号
            packageReqHandler.SetParameter("nonce_str", nonceStr);              //随机字符串
            string sign = packageReqHandler.CreateMd5Sign("key", TenPayV3Info.Key);
            packageReqHandler.SetParameter("sign", sign);	                    //签名

            string data = packageReqHandler.ParseXML();

            var result = TenPayV3.CloseOrder(data);
            var res = XDocument.Parse(result);
            string openid = res.Element("xml").Element("openid").Value;

            return base.Content(openid);
        }

        /// <summary>
        /// 退款申请接口
        /// </summary>
        /// <returns>actuon</returns>
        public ActionResult Refund()
        {
            try
            {
                WeixinTrace.SendCustomLog("进入退款流程", "1");

                string nonceStr = TenPayV3Util.GetNoncestr();

                string outTradeNo = base.HttpContext.Session.GetString("BillNo");

                WeixinTrace.SendCustomLog("进入退款流程", "2 outTradeNo：" + outTradeNo);

                string outRefundNo = "OutRefunNo-" + SystemTime.Now.Ticks;
                int totalFee = int.Parse(base.HttpContext.Session.GetString("BillFee"));
                int refundFee = totalFee;
                string opUserId = TenPayV3Info.MchId;
                string domain = AppConfigConsts.AppDomain;
                var notifyUrl = $"{domain}/WX/RefundNotifyUrl";
                var dataInfo = new TenPayV3RefundRequestData(
                    TenPayV3Info.AppId,
                    TenPayV3Info.MchId,
                    TenPayV3Info.Key,
                    null,
                    nonceStr,
                    null,
                    outTradeNo,
                    outRefundNo,
                    totalFee,
                    refundFee,
                    opUserId,
                    null,
                    notifyUrl: notifyUrl);

                #region 旧方法

                //var cert = @"D:\cert\apiclient_cert_SenparcRobot.p12";//根据自己的证书位置修改
                //var password = TenPayV3Info.MchId; //默认为商户号，建议修改
                //var result = TenPayV3.Refund(dataInfo, cert, password);
                #endregion

                #region 新方法（Senparc.Weixin v6.4.4+）
                var result = TenPayV3.Refund(dataInfo); // 证书地址、密码，在配置文件中设置，并在注册微信支付信息时自动记录
                #endregion

                WeixinTrace.SendCustomLog("进入退款流程", "3 Result：" + result.ToJson());

                return base.Content(string.Format("退款结果：{0} {1}。您可以刷新当前页面查看最新结果。", result.result_code, result.err_code_des));

                //return Json(result, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex));

                throw;
            }

            #region 原始方法

            //RequestHandler packageReqHandler = new RequestHandler(null);

            //设置package订单参数
            //packageReqHandler.SetParameter("appid", TenPayV3Info.AppId);		 //公众账号ID
            //packageReqHandler.SetParameter("mch_id", TenPayV3Info.MchId);	     //商户号
            //packageReqHandler.SetParameter("out_trade_no", "124138540220170502163706139412"); //填入商家订单号
            ////packageReqHandler.SetParameter("out_refund_no", "");                //填入退款订单号
            //packageReqHandler.SetParameter("total_fee", "");                    //填入总金额
            //packageReqHandler.SetParameter("refund_fee", "100");                //填入退款金额
            //packageReqHandler.SetParameter("op_user_id", TenPayV3Info.MchId);   //操作员Id，默认就是商户号
            //packageReqHandler.SetParameter("nonce_str", nonceStr);              //随机字符串
            //string sign = packageReqHandler.CreateMd5Sign("key", TenPayV3Info.Key);
            //packageReqHandler.SetParameter("sign", sign);	                    //签名
            ////退款需要post的数据
            //string data = packageReqHandler.ParseXML();

            ////退款接口地址
            //string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            ////本地或者服务器的证书位置（证书在微信支付申请成功发来的通知邮件中）
            //string cert = @"D:\cert\apiclient_cert_SenparcRobot.p12";
            ////私钥（在安装证书时设置）
            //string password = TenPayV3Info.MchId;
            //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            ////调用证书
            //X509Certificate2 cer = new X509Certificate2(cert, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

            //#region 发起post请求
            //HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
            //webrequest.ClientCertificates.Add(cer);
            //webrequest.Method = "post";

            //byte[] postdatabyte = Encoding.UTF8.GetBytes(data);
            //webrequest.ContentLength = postdatabyte.Length;
            //Stream stream;
            //stream = webrequest.GetRequestStream();
            //stream.Write(postdatabyte, 0, postdatabyte.Length);
            //stream.Close();

            //HttpWebResponse httpWebResponse = (HttpWebResponse)webrequest.GetResponse();
            //StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
            //string responseContent = streamReader.ReadToEnd();
            //#endregion

            //// var res = XDocument.Parse(responseContent);
            ////string openid = res.Element("xml").Element("out_refund_no").Value;
            //return Content("申请成功：<br>" + HttpUtility.RequestUtility.HtmlEncode(responseContent));

            #endregion

        }

        /// <summary>
        /// 退款通知地址
        /// </summary>
        /// <returns>result</returns>
        public ActionResult RefundNotifyUrl()
        {
            WeixinTrace.SendCustomLog("RefundNotifyUrl被访问", "IP" + base.HttpContext.UserHostAddress()?.ToString());

            string responseCode = "FAIL";
            string responseMsg = "FAIL";
            try
            {
                ResponseHandler resHandler = new ResponseHandler(null);

                string return_code = resHandler.GetParameter("return_code");
                string return_msg = resHandler.GetParameter("return_msg");

                WeixinTrace.SendCustomLog("跟踪RefundNotifyUrl信息", resHandler.ParseXML());

                if (return_code == "SUCCESS")
                {
                    responseCode = "SUCCESS";
                    responseMsg = "OK";

                    string appId = resHandler.GetParameter("appid");
                    string mch_id = resHandler.GetParameter("mch_id");
                    string nonce_str = resHandler.GetParameter("nonce_str");
                    string req_info = resHandler.GetParameter("req_info");

                    var decodeReqInfo = TenPayV3Util.DecodeRefundReqInfo(req_info, TenPayV3Info.Key);
                    var decodeDoc = XDocument.Parse(decodeReqInfo);

                    //获取接口中需要用到的信息
                    string transaction_id = decodeDoc.Root.Element("transaction_id").Value;
                    string out_trade_no = decodeDoc.Root.Element("out_trade_no").Value;
                    string refund_id = decodeDoc.Root.Element("refund_id").Value;
                    string out_refund_no = decodeDoc.Root.Element("out_refund_no").Value;
                    int total_fee = int.Parse(decodeDoc.Root.Element("total_fee").Value);
                    int? settlement_total_fee = decodeDoc.Root.Element("settlement_total_fee") != null
                            ? int.Parse(decodeDoc.Root.Element("settlement_total_fee").Value)
                            : null as int?;
                    int refund_fee = int.Parse(decodeDoc.Root.Element("refund_fee").Value);
                    int tosettlement_refund_feetal_fee = int.Parse(decodeDoc.Root.Element("settlement_refund_fee").Value);
                    string refund_status = decodeDoc.Root.Element("refund_status").Value;
                    string success_time = decodeDoc.Root.Element("success_time").Value;
                    string refund_recv_accout = decodeDoc.Root.Element("refund_recv_accout").Value;
                    string refund_account = decodeDoc.Root.Element("refund_account").Value;
                    string refund_request_source = decodeDoc.Root.Element("refund_request_source").Value;

                    //进行业务处理
                }
            }
            catch (Exception ex)
            {
                responseMsg = ex.Message;
                WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex));
            }

            string xml = string.Format(
                @"<xml>
<return_code><![CDATA[{0}]]></return_code>
<return_msg><![CDATA[{1}]]></return_msg>
</xml>", responseCode,
                responseMsg);
            return base.Content(xml, "text/xml");
        }
        #endregion

        ///// <summary>
        ///// 用户发送消息后，微信平台自动Post一个请求到这里，并等待响应XML。
        ///// PS：此方法为简化方法，效果与OldPost一致。
        ///// v0.8之后的版本可以结合Senparc.Weixin.MP.MvcExtension扩展包，使用WeixinResult，见MiniPost方法。
        ///// </summary>
        //[HttpPost]
        //[ActionName("Index")]
        //public ActionResult Post(PostModel postModel)
        //{
        //    if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token))
        //    {
        //        return base.Content("参数错误！");
        //    }

        //    #region 打包 PostModel 信息

        //    postModel.Token = Token; //根据自己后台的设置保持一致
        //    postModel.EncodingAESKey = EncodingAESKey; //根据自己后台的设置保持一致
        //    postModel.AppId = AppId; //根据自己后台的设置保持一致（必须提供）

        //    #endregion

        //    //v4.2.2之后的版本，可以设置每个人上下文消息储存的最大数量，防止内存占用过多，如果该参数小于等于0，则不限制
        //    var maxRecordCount = 10;

        //    //自定义MessageHandler，对微信请求的详细判断操作都在这里面。
        //    var messageHandler = new CustomMessageHandler(Request.GetRequestMemoryStream(), postModel, maxRecordCount);

        //    #region 设置消息去重

        //    /* 如果需要添加消息去重功能，只需打开OmitRepeatedMessage功能，SDK会自动处理。
        //     * 收到重复消息通常是因为微信服务器没有及时收到响应，会持续发送2-5条不等的相同内容的RequestMessage*/
        //    messageHandler.OmitRepeatedMessage = true;//默认已经开启，此处仅作为演示，也可以设置为false在本次请求中停用此功能

        //    #endregion

        //    try
        //    {
        //        messageHandler.SaveRequestMessageLog();//记录 Request 日志（可选）

        //        messageHandler.Execute(); //执行微信处理过程（关键）

        //        messageHandler.SaveResponseMessageLog(); //记录 Response 日志（可选）

        //        //return Content(messageHandler.ResponseDocument.ToString());//v0.7-
        //        //return new WeixinResult(messageHandler);//v0.8+
        //        return new FixWeixinBugWeixinResult(messageHandler); //为了解决官方微信5.0软件换行bug暂时添加的方法，平时用下面一个方法即可
        //    }
        //    catch (Exception ex)
        //    {
        //        #region 异常处理
        //        WeixinTrace.Log("MessageHandler错误：{0}", ex.Message);

        //        using (TextWriter tw = new StreamWriter(Server.GetMapPath("~/App_Data/Error_" + _getRandomFileName() + ".txt")))
        //        {
        //            tw.WriteLine("ExecptionMessage:" + ex.Message);
        //            tw.WriteLine(ex.Source);
        //            tw.WriteLine(ex.StackTrace);

        //            //tw.WriteLine("InnerExecptionMessage:" + ex.InnerException.Message);

        //            if (messageHandler.ResponseDocument != null)
        //            {
        //                tw.WriteLine(messageHandler.ResponseDocument.ToString());
        //            }

        //            if (ex.InnerException != null)
        //            {
        //                tw.WriteLine("========= InnerException =========");
        //                tw.WriteLine(ex.InnerException.Message);
        //                tw.WriteLine(ex.InnerException.Source);
        //                tw.WriteLine(ex.InnerException.StackTrace);
        //            }

        //            tw.Flush();
        //            tw.Close();
        //        }

        //        return base.Content(string.Empty);
        //        #endregion
        //    }
        //}

        ///// <summary>
        ///// 最简化的处理流程（不加密）
        ///// </summary>
        //[HttpPost]
        //[ActionName("MiniPost")]
        //public ActionResult MiniPost(PostModel postModel)
        //{
        //    if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token))
        //    {
        //        //return Content("参数错误！");//v0.7-
        //        return new WeixinResult("参数错误！"); //v0.8+
        //    }

        //    postModel.Token = Token;
        //    postModel.EncodingAESKey = EncodingAESKey;//根据自己后台的设置保持一致
        //    postModel.AppId = AppId;//根据自己后台的设置保持一致

        //    var messageHandler = new CustomMessageHandler(Request.GetRequestMemoryStream(), postModel, 10);

        //    messageHandler.Execute();//执行微信处理过程

        //    //return Content(messageHandler.ResponseDocument.ToString());//v0.7-
        //    //return new WeixinResult(messageHandler);//v0.8+
        //    return new FixWeixinBugWeixinResult(messageHandler);//v0.8+
        //}

        /*
         * v0.3.0之前的原始Post方法见：WeixinController_OldPost.cs
         *
         * 注意：虽然这里提倡使用CustomerMessageHandler的方法，但是MessageHandler基类最终还是基于OldPost的判断逻辑，
         * 因此如果需要深入了解Senparc.Weixin.MP内部处理消息的机制，可以查看WeixinController_OldPost.cs中的OldPost方法。
         * 目前为止OldPost依然有效，依然可用于生产。
         */

        /// <summary>
        /// 为测试并发性能而建
        /// </summary>
        /// <returns>代码修复</returns>
        public ActionResult ForTest()
        {
            //异步并发测试（提供给单元测试使用）
            DateTime begin = DateTime.Now;
            int t1, t2, t3;
            System.Threading.ThreadPool.GetAvailableThreads(out t1, out t3);
            System.Threading.ThreadPool.GetMaxThreads(out t2, out t3);
            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5));
            DateTime end = DateTime.Now;
            var thread = System.Threading.Thread.CurrentThread;
            var result = string.Format(
                "TId:{0}\tApp:{1}\tBegin:{2:mm:ss,ffff}\tEnd:{3:mm:ss,ffff}\tTPool：{4}",
                    thread.ManagedThreadId,
                    base.HttpContext.GetHashCode(),
                    begin,
                    end,
                    t2 - t1
                    );
            return base.Content(result);
        }

    }

    /// <summary>
    /// 商品实体类
    /// </summary>
    public class ProductModel
    {
        /// <summary>
        /// 产品ID
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 产品名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 产品价格
        /// </summary>
        public decimal Price { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProductModel"/> class.
        /// 产品模型
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="name">姓名</param>
        /// <param name="price">价格</param>
        public ProductModel(int id, string name, decimal price)
        {
            this.Id = id;
            this.Name = name;
            this.Price = price;
        }

        private static List<ProductModel> ProductList { get; set; }

        /// <summary>
        /// 获取产品列表
        /// </summary>
        /// <returns>产品信息</returns>
        public static List<ProductModel> GetFakeProductList()
        {
            var list = ProductList ?? new List<ProductModel>()
            {
                new ProductModel(1, "产品1", (decimal)1.00),
                new ProductModel(2, "产品2", (decimal)2.00),
                new ProductModel(3, "产品3", (decimal)3.00),
                new ProductModel(4, "产品4", (decimal)4.00)
            };
            ProductList = ProductList ?? list;

            return list;
        }
    }

    /// <summary>
    /// 支付成功模板消息（购买成功通知）
    /// </summary>
    public class WeixinTemplate_PaySuccess : TemplateMessageBase
    {
        private const string TEMPLATEID = "66Gf81swxfWt_P_HkH0Bapvj1nlpiWGmEkXDeCvWcVo"; //每个公众号都不同，需要根据实际情况修改

        /// <summary>
        /// 名称
        /// </summary>
        public TemplateDataItem Name { get; set; }

        /// <summary>
        /// Time
        /// </summary>
        public TemplateDataItem Remark { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="WeixinTemplate_PaySuccess"/> class.
        /// 构造方法
        /// </summary>
        /// <param name="url">回调Url</param>
        /// <param name="productName">产品名称</param>
        /// <param name="notice">通知</param>
        public WeixinTemplate_PaySuccess(string url, string productName, string notice)
            : base(TEMPLATEID, url, "购买成功通知")
        {
            this.Name = new TemplateDataItem(productName);
            this.Remark = new TemplateDataItem(notice);
        }
    }
}
